<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 * @author   howe <howe1995@163.com>
 */
use App\Services\QueueService;
use Hyperf\AsyncQueue\Job;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Database\Model\Collection;
use Hyperf\Database\Model\Model;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Redis\Redis;
use Hyperf\Server\ServerFactory;
use Hyperf\Stringable\Str;
use Overtrue\Pinyin\Pinyin;
use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\SimpleCache\CacheInterface;
use Swoole\Websocket\Frame;
use Swoole\WebSocket\Server as WebSocketServer;

use function Hyperf\Config\config;

if (! function_exists('getClientIp')) {
    function getClientIp(): string
    {
        try {
            $request = ApplicationContext::getContainer()->get(RequestInterface::class);
            $headers = $request->getHeaders();
            if (! empty($headers['x-forwarded-for'][0])) {
                return $headers['x-forwarded-for'][0];
            }
            if (! empty($headers['x-real-ip'][0])) {
                return $headers['x-real-ip'][0];
            }
            $serverParams = $request->getServerParams();
            return $serverParams['remote_addr'] ?? '127.0.0.1';
        } catch (Throwable $e) {
            logInfo('getClientIp', $e->getMessage());
            return '172.21.0.1';
        }

        /*
         * nginx 配置
         * location / {
         * # proxy host and ip information
         * proxy_set_header Host $http_host;
         * proxy_set_header X-Real-IP $remote_addr;
         * proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         *
         * # proxy
         * proxy_pass http://127.0.0.1:9501;
         * }
         */
    }
}

if (! function_exists('json2array')) {
    /**
     * Note - json转数组
     * DateTime 2024/9/27 11:06
     * User Admin.
     * @param mixed $json_str
     * @return array
     */
    function json2array($json_str)
    {
        // 检查是否已经是数组或对象
        if (is_array($json_str) || is_object($json_str)) {
            return (array) $json_str;
        }
        // 尝试将字符串转换为数组
        $decoded = json_decode($json_str, true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return json2array($decoded); // 递归处理解码后的数据
        }
        return [];
    }
}

if (! function_exists('logInfo')) {
    /**
     * Note - 记录日志
     * DateTime 2024/8/7 16:39
     * User Admin.
     * @param string $fileName 不带后缀的文件名
     * @param array $content 日志内容
     * @param string $label 日志标签
     * @return bool
     */
    function logInfo($fileName, mixed $content = 'tamgo', string $label = '')
    {
        if (is_string($content)) {
            $content = 'string [' . date('Y-m-d H:i:s') . '] ' . $label . ' ' . $content . PHP_EOL;
        } else {
            $content = gettype($content) . '[' . date('Y-m-d H:i:s') . '] ' . $label . ' ' . json_encode($content, JSON_UNESCAPED_UNICODE) . PHP_EOL;
        }
        $filePath = BASE_PATH . '/runtime/logs/' . date('Ymd') . '/' . $fileName . '.log';
        $dirPath = dirname($filePath);
        if (! file_exists($dirPath)) {
            mkdir($dirPath, 0755, true); // 0755 表示权限，true 表示递归创建
        }
        // 写入日志
        $result = file_put_contents($filePath, $content, FILE_APPEND);

        return $result !== false;
    }
}

if (! function_exists('modelToArray')) {
    /**
     * Note - Hyperf模型对象转数组
     * DateTime 2024/7/17 10:44
     * User Admin.
     * @param mixed $model
     * @return array|void
     */
    function modelToArray($model)
    {
        if ($model instanceof Model || $model instanceof Collection) {
            return $model->toArray();
        }
        if (is_object($model)) {
            $model = (array) $model;
        }
        if (is_array($model)) {
            foreach ($model as $key => $value) {
                $model[$key] = modelToArray($value);
            }
        }
        return $model;
    }
}

if (! function_exists('getMillisecond')) {
    function getMillisecond()
    {
        $microtime = microtime(true);
        $millisecondTimestamp = round($microtime * 100);
        return intval($millisecondTimestamp);
        // list($msec, $sec) = explode(' ', microtime());
        // $msectime =  sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        // $msectimes = substr($msectime,0,13);
        // return intval($msectimes);
    }
}

if (! function_exists('formatDate')) {
    /**
     * Note - 时间格式化为今天、昨天、其他
     * DateTime 2024/8/20 10:34
     * User Admin.
     * @param mixed $time
     * @return array|string
     */
    function formatDate($time)
    {
        $today_time = strtotime(date('Y-m-d 00:00:00'));
        $yesterday_time = strtotime(date('Y-m-d 00:00:00', strtotime('-1 days')));
        if ($time >= $today_time) {
            return '今天' . date('H:i:s', $time);
        }
        if ($time >= $yesterday_time) {
            return '昨天' . date('H:i:s', $time);
        }
        return date('Y-m-d H:i:s', $time);
    }
}

if (! function_exists('formatSecond')) {
    /**
     * Note - 将秒格式化为 00:00:00
     * DateTime 2024/8/20 10:40
     * User Admin.
     * @param mixed $seconds
     * @return string
     */
    function formatSecond($seconds)
    {
        if ($seconds == 0) {
            return '0';
        }
        if ($seconds >= 3600) {
            $time = date('H:i:s', $seconds);
        } elseif ($seconds >= 60) {
            $time = date('i:s', $seconds);
        } else {
            $time = date('00:s', $seconds);
        }
        return $time;
    }
}

if (! function_exists('dispatch')) {
    // 异步任务
    function dispatch(Job $job, int $second = 0)
    {
        return di()->get(QueueService::class)->push(new $job(), $second);
    }
}

if (! function_exists('rand_avatar')) {
    // 生成随机头像
    function rand_avatar(int|string $str): string
    {
        $md5Str = md5($str);
        return "https://api.multiavatar.com/{$md5Str}.png";
    }
}

if (! function_exists('is_mobile')) {
    // 手机号判断
    function is_mobile(int|string $str): bool
    {
        $pattern = '/^1[3-9]\\d{9}$/';
        return preg_match($pattern, $str) > 0;
    }
}

if (! function_exists('group_by_first_char')) {
    // 通过中英文的拼音英文首字母分组
    function group_by_first_char(array $array, string $field): array
    {
        $grouped = [];

        // 小助手排前面
        $assistantIds = get_assistant_ids();
        foreach ($array as $k => $v) {
            if (in_array($v['friend'], $assistantIds)) {
                unset($array[$k]);
                $firstChar = 'A';
                if (! isset($grouped[$firstChar])) {
                    $grouped[$firstChar] = [];
                }
                $grouped[$firstChar][] = $v;
            }
        }
        foreach ($array as $item) {
            $str = $item[$field];
            if (preg_match('/^[\x{4e00}-\x{9fa5}]/u', $str)) { // 匹配中文字符
                $str = (string) Pinyin::sentence($str);
            }

            $firstChar = strtoupper($str[0]);
            if (! ctype_upper($firstChar)) {
                $firstChar = 'A';
            }

            if (! isset($grouped[$firstChar])) {
                $grouped[$firstChar] = [];
            }
            $grouped[$firstChar][] = $item;
        }
        return $grouped;
    }
}

if (! function_exists('is_linux')) {
    /**
     * 判断当前操作系统是否为 Linux.
     */
    function is_linux(): bool
    {
        return stripos(PHP_OS, 'Linux') !== false || stripos(php_uname('s'), 'Linux') !== false;
    }
}

if (! function_exists('get_assistant_ids')) {
    function get_assistant_ids(): array
    {
        return array_keys(config('assistant'));
    }
}

if (! function_exists('get_page_info')) {
    function get_page_info(int $page, int $limit, int $total): array
    {
        return [
            'total' => $total,
            'total_page' => ceil($total / $limit),
            'current_page' => $page,
        ];
    }
}

if (! function_exists('di')) {
    /**
     * 容器实例.
     */
    function di(): ContainerInterface
    {
        return ApplicationContext::getContainer();
    }
}

if (! function_exists('redis')) {
    /**
     * Redis 客户端实例.
     */
    function redis()
    {
        return di()->get(Redis::class);
    }
}

if (! function_exists('server')) {
    /**
     * Server 实例 基于 Swoole Server.
     */
    function server()
    {
        return di()->get(ServerFactory::class)->getServer()->getServer();
    }
}

if (! function_exists('frame')) {
    /**
     * WebSocket frame 实例.
     */
    function frame()
    {
        return di()->get(Frame::class);
    }
}

if (! function_exists('websocket')) {
    /**
     * WebSocketServer 实例.
     */
    function websocket()
    {
        return di()->get(WebSocketServer::class);
    }
}

if (! function_exists('cache')) {
    /**
     * 缓存实例 简单的缓存.
     */
    function cache()
    {
        return di()->get(CacheInterface::class);
    }
}

if (! function_exists('event')) {
    /**
     * Dispatch an event and call the listeners.
     */
    function event()
    {
        return di()->get(EventDispatcherInterface::class);
    }
}

if (! function_exists('stdout_log')) {
    /**
     * 控制台日志.
     */
    function stdout_log()
    {
        return di()->get(StdoutLoggerInterface::class);
    }
}

if (! function_exists('response')) {
    /**
     * 请求响应.
     */
    function response()
    {
        return di()->get(ResponseInterface::class);
    }
}

if (! function_exists('create_image_name')) {
    /**
     * 随机生成图片名.
     *
     * @param string $ext 图片后缀名
     * @param array $filesize 图片文件大小信息
     */
    function create_image_name(string $ext, array $filesize): string
    {
        return uniqid() . Str::random() . '_' . $filesize[0] . 'x' . $filesize[1] . '.' . $ext;
    }
}

if (! function_exists('create_random_filename')) {
    /**
     * 生成随机文件名.
     */
    function create_random_filename(string $ext): string
    {
        $ext = $ext ? '.' . $ext : '';
        return Str::random(10) . uniqid() . $ext;
    }
}

if (! function_exists('check_int')) {
    /**
     * 判断0或正整数.
     * @param int|string $value 验证字符串
     * @param bool $isZero 判断是否可为0
     */
    function check_int(int|string $value, bool $isZero = false): bool
    {
        $reg = $isZero ? '/^[+]{0,1}(\d+)$/' : '/^[1-9]\d*$/';
        return is_numeric($value) && preg_match($reg, $value);
    }
}
